#include "../../include/DatabasePool.hpp"
#include <cppconn/statement.h>
#include <iostream>

// 静态方法实现
// 单例模式
/** 
 * 利用C++11静态局部变量的线程安全特性，避免双重检查锁定的复杂性
 * 首次调用时构造实例，程序结束时自动销毁
 */
ConnectionPool* ConnectionPool::getInstance() {
	static ConnectionPool instance;
	return &instance;
}

/* 连接池初始化方法（线程安全）
 * @param timeout 单位毫秒，用于设置连接超时等参数
 * 注意：默认参数只在声明处指定，实现不应重复默认值（已移除port的默认值）
 */
void ConnectionPool::init(const string& host, const string& user, const string& pwd, const string& dbname, unsigned int port, int maxConn, int timeout) {
	// 上锁
	lock_guard<mutex> lock(mutex_);
	this->host_ = host;
	this->user_ = user;
    this->pwd_ = pwd;
    this->dbName_ = dbname;
    this->port_ = port;
    this->maxConn_ = maxConn;
    this->connTimeout_ = timeout;

	// 尝试做连接操作 遭了就抛异常
	try {
		// 获取MySQL驱动实例（线程安全操作）
		driver_ = get_driver_instance();
		// 先创建一半连接 怕浪费
		/* 预热连接池：
         * 策略优点：
         * 1. 避免启动时全部连接的开销
         * 2. 留有扩容空间应对突发请求
         * 3. 平衡资源使用和响应速度
         */
		for (int i = 0; i < maxConn_ / 2; i++) {
			Connection* conn = creatConnection();
			if (conn && !conn->isClosed()) {
				// 非空就进连接池队列
				connQueue_.push(conn);
				++curConn_;		// 原子操作
			}
		}
	} catch (SQLException& e) {
		cerr << "MySQL 初始化失败: " << e.what() << endl;
		throw;		// 传播异常让调用方处理
	}
}

// 创建单个物理连接
Connection* ConnectionPool::creatConnection() {
	try {
		string url = "tcp://" + host_ + ":" + to_string(port_);
		// 建立TCP连接并进行认证 url 是 要带tcp字样的string
		Connection* conn = driver_->connect(url, user_, pwd_);
		conn->setSchema(dbName_);
		// 自动重连  方便一点
		conn->setClientOption("OPT_RECONNECT",to_string(true));
		return conn;
	} catch (SQLException& e) {
		cerr << "创建连接失败: " << e.what() << "(MySQL错误状态码: " << e.getErrorCode() << ", SQL 状态: " << e.getSQLState() << ")" << endl;
		return nullptr;
	}
}

bool ConnectionPool::validateConnection(Connection* conn) {
	if (conn == nullptr || conn->isClosed()) 	return false;

	// 判断完就抓异常
	/* 通过简单查询验证连接可用性
     * 使用SELECT 1原因：
     * 1. 最轻量级的SQL语句
     * 2. 所有MySQL版本支持
     * 3. 能检测网络层和服务器端问题
     */
	try {
		unique_ptr<Statement> stmt(conn->createStatement());
		stmt->execute("SELECT 1");
		return true;
	} catch (... ) {
		return false;
	}
}

// 核心方法：获取连接（带超时机制）
shared_ptr<Connection> ConnectionPool::getConnection(int timeout) {
	// 先上锁 保证单一线程获取连接 避免竞态条件
	// 唯一锁支持 条件变量 操作
	unique_lock<mutex> lock(mutex_);

	// 双重验证连接池状态
    if(curConn_ == 0 && connQueue_.empty()) {
        throw std::runtime_error("连接池未初始化");
    }

	// 队列非空 || 可以创建新连接
	// wait_for 中给lambda直接说明条件
	if (!cond_.wait_for(lock, chrono::milliseconds(timeout), [this] {
		return !connQueue_.empty() || curConn_ < maxConn_;
	})) {
		cerr << "获取连接超时 (最大等待: " << timeout << " ms)" << endl;
		return nullptr;
	}
	// 顺序
	/**
	 * 1. 有空闲连接就先用
	 * 2. 没有就等着
	 * 3. 如果没有连接 允许条件下 create 一个新的
	 */
	if (!connQueue_.empty()) {
		Connection* conn = connQueue_.front();
		connQueue_.pop();

		/* 双重验证模式：
         * 虽然从队列取出，但可能在此期间连接失效
         * 特别是MySQL服务器重启或网络波动时
         */
		if (!validateConnection(conn)) {
			delete conn;
			--curConn_;
			lock.unlock();	// 死锁就完了
			return getConnection(timeout);		// 递归重试
		}
		// 给返回值 还是lambda来给出 share_ptr 的处理形式
		// 删除器 是要 将连接从队列中取出 不是直接关闭 需要自定义
		/* 智能指针自定义删除器：
         * 1. 不是直接关闭连接
         * 2. 将有效连接返回到池中
         * 3. 销毁无效连接并更新计数
         */
		return shared_ptr<Connection>(conn, [this](Connection* conn) {
			// 还是加锁
			unique_lock<mutex> lock(mutex_);
			if (validateConnection(conn)) 	connQueue_.push(conn);
			else {
				delete conn;
				--curConn_;
			}
			cond_.notify_one();
		});
	}

	// 队列中 连接数 少于 最大连接数 可以创建新连接
	if (curConn_ < maxConn_) {
		Connection* conn = creatConnection();
		if (conn != nullptr) {
			++curConn_;
			return shared_ptr<Connection>(conn, [this](Connection* conn) {
				// 还是加锁
				unique_lock<mutex> lock(mutex_);
				if (validateConnection(conn)) 	connQueue_.push(conn);
				else {
					delete conn;
					--curConn_;
				}
				cond_.notify_one();
			});
		}
	}
	// 什么操作都没得到 那就是空
	// 理论上不会执行到此处（条件变量已保证前置条件）
	return nullptr;
}

ConnectionPool::PoolStats ConnectionPool::getStats() const {
	lock_guard<mutex> lock(mutex_);
	// 两个int 别忘记转换
	return {curConn_, static_cast<int>(connQueue_.size())};
}

// 析构时释放所有连接
ConnectionPool::~ConnectionPool() {
	// 迭代释放资源
	while (!connQueue_.empty()) {
		// 迭代从队列中 pop 连接
		Connection* conn = connQueue_.front();
		connQueue_.pop();
		// 额外还有一个单独判断一下最后一个队头的连接
		if (!conn->isClosed()) {
				conn->close(); // 发送QUIT命令给MySQL服务器
		}
		// 没关就手动关一下 然后释放
		delete conn;
	}
	
	// 析构完之后肯定连接数为0
	curConn_ = 0;	
}	


// !重载
bool ConnectionPool::operator!() const {
    // 判断连接池是否有效（示例逻辑，根据实际需求调整）
    return connQueue_.empty() && curConn_ == 0;
}

bool ConnectionPool::isValid() const { 
    std::lock_guard<std::mutex> lock(mutex_);
    return !connQueue_.empty() || curConn_ > 0;
}